﻿#include "StdAfx.h"
#include <stdio.h>
#include "ATMFaceSelect.h"

#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif
#define MAXINIMG	10


const char* cascade_name_face = "c:/data/haarcascade_frontalface_alt.xml";

//////////////////////Michael Add Eye-Mouth Analysis/////////////////////////////////////////
#ifdef SAVE_FACEANA_DEBUG_INFO
CString g_curDebugInfoFilePrefix = _T("");
void setCurDebugInfoPath( CString& strPrefix )
{
	g_curDebugInfoFilePrefix = strPrefix;
}
#endif

const char* cascade_name_eye = "C:/data/LEye18x12.xml";
const int nRgnBound_leye[4] = { 0, 0, 50, 50 };//�������Ķ��Χ���������ٷֱ�

const char* cascade_name_reye = "C:/data/REye18x12.xml";
const int nRgnBound_reye[4] = { 50, 0, 100, 50 };//�������Ķ��Χ���������ٷֱ�

const char* cascade_name_mouth = "C:/data/Mouth25x15.xml";
const int nRgnBound_mouth[4] = { 0, 50, 100, 100 };//�������Ķ��Χ���������ٷֱ�
/////////////////////End -- Michael Add Eye-Mouth Analysis///////////////////////////////////


//////////////////////Yuki Add Upperbody Analysis/////////////////////////////////////////
const char* cascade_name_upperbody = "c:/data/haarcascade_upperbody.xml";
//////////////////////End--Yuki Add Upperbody Analysis/////////////////////////////////////////


void CATMFaceSelect::InitClass()//Michael Add 20090507
{
	m_cvSeqStorage = cvCreateMemStorage(0);
	m_cvImageSeq = cvCreateSeq(0, sizeof(CvSeq), sizeof(IplImage*), m_cvSeqStorage);
	m_cvSeqFaceSeqStorage = cvCreateMemStorage(0);
	m_cvSeqFaceSeq = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvSeq*), m_cvSeqFaceSeqStorage);
	m_cvSeqFaceStorageStorage = cvCreateMemStorage(0);
	m_cvSeqFaceStorage = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvMemStorage*), \
		m_cvSeqFaceStorageStorage);

	InitCascade(cascade_name_face, m_cascade_face, m_casMem_face);

	initSubFaceFeatureCascade( );//Michael Add Eye-Mouth Analysis

	m_outputDir[0] = 0;
	m_resString[0] = 0;

	m_ExRatio_t = 0.1f;
	m_ExRatio_b = 0.1f;
	m_ExRatio_l = 0.05;
	m_ExRatio_r = 0.05f;
}

CATMFaceSelect::CATMFaceSelect(void)
: m_cvSeqStorage(NULL)
, m_cvImageSeq(NULL)
, m_cascade_face(NULL)
, m_cvSeqFaceSeq(NULL)
, m_cvSeqFaceSeqStorage(NULL)
, m_cvSeqFaceStorage(NULL)
, m_cvSeqFaceStorageStorage(NULL)
, m_pDiffRectStorage(NULL)
, m_pDiffJudgeStorage(NULL)
, m_sqDiffFaceRect(NULL)
, m_sqDiffFaceJudge(NULL)
, m_pHistStorage(NULL)
, m_sqHist(NULL)
, m_pImgNoStorage(NULL)
, m_sqImgNo(NULL)
, m_dSglBkgProportion(0.15)
, m_dFaceProportion(0.5)
, m_bScaleFaceDetection(1)
, m_dScale(0.5)
, m_dForeheadNoise(0.75)
, m_dUpBkgNoise(0.13)
, m_dSideBkgNoise(0.05)
, m_dEarNoise(0.30)
, m_iFaceSize(80/*30*/)//Michael Change 20090508 -- 30 -> 60
, m_iSFactorValv(23)
, m_iSizeWeight(5)
, m_cascade_eye(NULL)//left eye
, m_cascade_reye(NULL)
, m_cascade_mouth(NULL)
, m_storage_subfacefeature(NULL)
, m_dFaceChangeRatio(2.0)
, m_rcROI( cvRect(0,0,0,0) )
, m_casMem_face(NULL)
, m_casMem_eye(NULL)
, m_casMem_reye(NULL)
, m_casMem_mouth(NULL)
, m_iLightCondition(0)
, m_bDebugForBkgAna(0)
{
	InitClass();//Michael Change 20090507
}

CATMFaceSelect::~CATMFaceSelect(void)
{
	ReleaseCascade(m_cascade_face, m_casMem_face);
	ReleaseImageSeq();
	ReleaseFaceSeq();
	ReleaseStorageSeq();

	releaseSubFaceFeatureCascade( );//Michael Add Eye-Mouth Analysis
}

void CATMFaceSelect::ReleaseImageSeq()
{
	IplImage **ppImage;
	for (int i=0; i<m_cvImageSeq->total; i++)
	{
		ppImage = CV_GET_SEQ_ELEM(IplImage*, m_cvImageSeq, i);
		cvReleaseImage(ppImage);
	}

	cvClearSeq(m_cvImageSeq);
	cvReleaseMemStorage(&m_cvSeqStorage);
	m_cvImageSeq = NULL;
	m_cvSeqStorage = NULL;
}

void CATMFaceSelect::ReleaseFaceSeq()
{
	CvSeq **ppSeq;
	for (int i=0; i<m_cvSeqFaceSeq->total; i++)
	{
		ppSeq = CV_GET_SEQ_ELEM(CvSeq*, m_cvSeqFaceSeq, i);
		cvClearSeq(*ppSeq);
	}
	cvClearSeq(m_cvSeqFaceSeq);
	cvReleaseMemStorage(&m_cvSeqFaceSeqStorage);
	m_cvSeqFaceSeq = NULL;
	m_cvSeqFaceSeqStorage = NULL;
}

void CATMFaceSelect::ReleaseStorageSeq()
{
	CvMemStorage **ppMemSeq;
	for (int i=0; i<m_cvSeqFaceStorage->total; i++)
	{
		ppMemSeq = CV_GET_SEQ_ELEM(CvMemStorage*, m_cvSeqFaceStorage, i);
		cvReleaseMemStorage(ppMemSeq);
	}
	cvClearSeq(m_cvSeqFaceStorage);
	cvReleaseMemStorage(&m_cvSeqFaceStorageStorage);
	m_cvSeqFaceStorage = NULL;
	m_cvSeqFaceStorageStorage = NULL;
}

IplImage* CATMFaceSelect::GetSubImage(IplImage* pOriImage, CvRect roi)
{
	IplImage * pSubImage = NULL;   

	cvSetImageROI(pOriImage, roi);
	pSubImage = cvCreateImage( cvSize(pOriImage->roi->width, pOriImage->roi->height), pOriImage->depth, pOriImage->nChannels );   
	pSubImage->origin = pOriImage->origin;   
	cvCopy(pOriImage, pSubImage);   
	cvResetImageROI(pOriImage);  

	return pSubImage;   
}

void CATMFaceSelect::ClearImgSeq()
{
	ClearImageSeq();
	ClearFaceSeq();
	ClearStorageSeq();
}

void CATMFaceSelect::ClearImageSeq()
{
	if( m_cvImageSeq )
	{
		IplImage **ppImage;
		for (int i=0; i<m_cvImageSeq->total; i++)
		{
			ppImage = CV_GET_SEQ_ELEM(IplImage*, m_cvImageSeq, i);
			cvReleaseImage(ppImage);
		}

		cvClearSeq(m_cvImageSeq);
	}

	//if( m_cvSeqStorage )
	//	cvClearMemStorage(m_cvSeqStorage);
}

void CATMFaceSelect::ClearFaceSeq()
{
	if( m_cvSeqFaceSeq )
	{
		CvSeq **ppSeq;
		for (int i=0; i<m_cvSeqFaceSeq->total; i++)
		{
			ppSeq = CV_GET_SEQ_ELEM(CvSeq*, m_cvSeqFaceSeq, i);
			cvClearSeq(*ppSeq);
		}
		cvClearSeq(m_cvSeqFaceSeq);
	}
	//if( m_cvSeqFaceSeqStorage )
	//	cvClearMemStorage(m_cvSeqFaceSeqStorage);

}

void CATMFaceSelect::ClearStorageSeq()
{
	if( m_cvSeqFaceStorage )
	{
		CvMemStorage **ppMemSeq;
		for (int i=0; i<m_cvSeqFaceStorage->total; i++)
		{
			ppMemSeq = CV_GET_SEQ_ELEM(CvMemStorage*, m_cvSeqFaceStorage, i);
			cvReleaseMemStorage(ppMemSeq);
		}
		cvClearSeq(m_cvSeqFaceStorage);
	}
}







CvSeq* CATMFaceSelect::FaceExtract( IplImage* pImage, CvMemStorage* pStorage )
{
	if (!pImage)
	{
		return 0;
	}

	if( !m_cascade_face )
	{
		return 0;
	}

	if( !pStorage )
	{
		return 0;
	}

	if( pImage->depth != 8 || pImage->nChannels != 3 )
	{
		return 0;
	}
	
	CvSize rcMinSize = cvSize( m_iFaceSize, m_iFaceSize );
	bool bScale = m_bScaleFaceDetection;
	double dScale = m_dScale;

	cvClearMemStorage( pStorage );

	CvSeq *pFaces = 0;
	IplImage* img = pImage;
	CvSeq* faces = 0;
	CvMemStorage* storage = cvCreateMemStorage(0);

	//Michael Add 2009508 -- Set ROI
	bool bGetSubImg = false;
	if( m_rcROI.width > 0 && m_rcROI.height > 0 )
	{
		if( m_rcROI.x >= 0 && m_rcROI.x + m_rcROI.width  < img->width
			&& m_rcROI.y >= 0 && m_rcROI.y + m_rcROI.height < img->height )
		{
			IplImage* imgSub = GetSubImage( img, m_rcROI );
			img = imgSub;
			imgSub = 0;

			bGetSubImg = true;
		}
	}
	//End -- Set ROI

	if (bScale == 1)
	{
		if( bGetSubImg )
		{
			IplImage* imgBak = cvCloneImage( img );
			cvReleaseImage( &img );
			img = NULL;
			ResizeImg( imgBak, img, dScale );
			cvReleaseImage( &imgBak );
		}
		else
		{
			ResizeImg( pImage, img, dScale );//������ Michael Change 20090508 -- ���ǻ���������������img�д洢������ͼ
		}

		//Michael Add 20090508 -- Convert rcMinSize
		rcMinSize.height = (int)(rcMinSize.height*dScale);
		rcMinSize.width = (int)(rcMinSize.width*dScale);
		//End -- Convert rcMinSize
	}

	IplImage* imgGray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
	cvCvtColor( img, imgGray, CV_BGR2GRAY );

	//cvEqualizeHist( imgGray, imgGray );
	faces = cvHaarDetectObjects(imgGray, m_cascade_face, storage,
		1.1, 3, CV_HAAR_DO_CANNY_PRUNING,
		rcMinSize );

	if (bScale == 1)
	{
		pFaces = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), pStorage );
		GetOrgRectSeq( pFaces, faces, dScale );
	} 
	else
	{
		pFaces = cvCloneSeq(faces, pStorage);
	}

	//Michael Add 20090508 -- Transfer face in cvROI to Whole Image
	if( bGetSubImg && pFaces )
	{
		int nFaceId  = 0;
		for( nFaceId = 0; nFaceId < pFaces->total; nFaceId++ )
		{
			CvRect* r = (CvRect*)cvGetSeqElem( pFaces, nFaceId );
			transferLocalRc2SceneRc( r, r, &m_rcROI, 1.0f );
		}
	}
	//End -- Transfer face in cvROI to Whole Image

	if ( bScale == 1 || bGetSubImg )//Michael Change 20090508 -- For GetSubImg
	{
		cvReleaseImage(&img);
	}
	cvReleaseImage( &imgGray );
	cvReleaseMemStorage(&storage);

	for( int nFaceId = 0; nFaceId < pFaces->total; nFaceId++ )
	{
		CvRect* r = (CvRect*)cvGetSeqElem( pFaces, nFaceId );
		GetUpperbody( r, cvGetSize(pImage), r);
	}

	return pFaces;
}

void CATMFaceSelect::ResizeImg( IplImage* imgOrg, IplImage* &imgDes, double dScale )
{
	imgDes = cvCreateImage( cvSize( cvRound (imgOrg->width * dScale),
		cvRound (imgOrg->height * dScale)),
		imgOrg->depth, imgOrg->nChannels );
	cvResize( imgOrg, imgDes, CV_INTER_LINEAR );

}

bool CATMFaceSelect::GetOrgRect( CvRect* rcOrg, const CvRect* rcScale, double dScale )
{
	if( !rcOrg ) return false;

	rcOrg->x = int( rcScale->x / dScale );
	rcOrg->y = int( rcScale->y / dScale );
	rcOrg->width = int( rcScale->width / dScale );
	rcOrg->height = int( rcScale->height / dScale );

	return true;
}

bool CATMFaceSelect::GetOrgRectSeq( CvSeq* orgFaces, const CvSeq* scaleFaces, double dScale )
{
	if( !orgFaces || !scaleFaces ) return false;

	cvClearSeq( orgFaces );

	int i = 0;
	int nfaces = scaleFaces->total;
	for( i = 0; i < nfaces; i++ )
	{
		CvRect* r = (CvRect*)cvGetSeqElem( scaleFaces, i );
		CvRect rScale = *r;
		GetOrgRect( &rScale, r, dScale );

		cvSeqPush( orgFaces, &rScale );
	}

	return true;
}


bool CATMFaceSelect::InitCascade( const char* cascade_name, CvHaarClassifierCascade* &cascade, CvMemStorage *casMem )
{
	if( !cascade )
	{
		casMem = cvCreateMemStorage(0);
		cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, casMem, 0, 0 );

		if( !cascade )
		{
			return false;
		}
	}
	return true;
}

void CATMFaceSelect::ReleaseCascade( CvHaarClassifierCascade* &cascade, CvMemStorage *casMem )
{
	if( cascade )
	{
		cvReleaseHaarClassifierCascade( &cascade );
		cvReleaseMemStorage(&casMem);
	}
}

////////////////////////////////////END -- �������///////////////////////////////////////////////
void CATMFaceSelect::MultiObjectInitialize()
{
	m_pDiffRectStorage = cvCreateMemStorage(0);
	m_pDiffJudgeStorage = cvCreateMemStorage(0);
	m_sqDiffFaceRect = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvRect), m_pDiffRectStorage);
	m_sqDiffFaceJudge = cvCreateSeq(0, sizeof(CvSeq), sizeof(double), m_pDiffJudgeStorage);

	m_pHistStorage = cvCreateMemStorage(0);
	m_sqHist = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvHistogram*), m_pHistStorage);

	m_pImgNoStorage = cvCreateMemStorage(0);
	m_sqImgNo = cvCreateSeq(0, sizeof(CvSeq), sizeof(int), m_pImgNoStorage);
}

void CATMFaceSelect::MultiObjectRelease()
{
	cvReleaseMemStorage(&m_pDiffRectStorage);
	cvReleaseMemStorage(&m_pDiffJudgeStorage);

	for (int i=0; i<(m_sqHist?m_sqHist->total:0); i++)
	{
		CvHistogram **ppHist = CV_GET_SEQ_ELEM(CvHistogram*, m_sqHist, i);
		cvReleaseHist(ppHist);
	}
	cvReleaseMemStorage(&m_pHistStorage);
	cvReleaseMemStorage(&m_pImgNoStorage);
}




bool CATMFaceSelect::initSubFaceFeatureCascade( )
{
	InitCascade( cascade_name_eye, m_cascade_eye, m_casMem_eye );
	InitCascade( cascade_name_reye, m_cascade_reye, m_casMem_reye );
	InitCascade( cascade_name_mouth, m_cascade_mouth, m_casMem_mouth );

	m_storage_subfacefeature = cvCreateMemStorage( 0 );

	return ( m_cascade_eye && m_cascade_reye && m_cascade_mouth );
}
void CATMFaceSelect::releaseSubFaceFeatureCascade( )
{
	ReleaseCascade( m_cascade_eye, m_casMem_eye );
	ReleaseCascade( m_cascade_reye, m_casMem_reye );
	ReleaseCascade( m_cascade_mouth, m_casMem_mouth );

	cvReleaseMemStorage( &m_storage_subfacefeature );
}

bool CATMFaceSelect::transferLocalRc2SceneRc( CvRect* rcInScene, CvRect* rcLocal, CvRect* rcRgn, double dScale )
{
	if( !rcInScene || !rcLocal || !rcRgn ) return false;

	rcInScene->x = int( rcRgn->x + rcLocal->x * dScale );
	rcInScene->y = int( rcRgn->y + rcLocal->y * dScale );
	rcInScene->width = int( rcLocal->width * dScale );
	rcInScene->height = int( rcLocal->height * dScale );

	return true;
}
//////////////////////////////////End -- Michael Add Eye-Mouth Analysis///////////////////////////////////////

////////////////////////////Yuki Add Upperbody Analysis/////////////////////////////////////////////
void CATMFaceSelect::GetUpperbody(  CvRect* pImage, CvSize rcSize,  CvRect* pUpperbody)
{
	pUpperbody->x = pImage->x - (int)(pImage->width * m_ExRatio_l);
	pUpperbody->x = pUpperbody->x < 0? 0:pUpperbody->x;
	pUpperbody->width = (int)(( m_ExRatio_l + m_ExRatio_r + 1.0 ) * pImage->width);
	pUpperbody->width = (pUpperbody->x+pUpperbody->width < rcSize.width)?pUpperbody->width:(rcSize.width - pUpperbody->x);
	
	pUpperbody->y = pImage->y - (int)(pImage->height * m_ExRatio_t);
	pUpperbody->y = pUpperbody->y < 0? 0:pUpperbody->y;
	pUpperbody->height = (int)(( m_ExRatio_t + m_ExRatio_b + 1.0f ) * pImage->height);
	pUpperbody->height = (pUpperbody->y+pUpperbody->height < rcSize.height)?pUpperbody->height:(rcSize.height - pUpperbody->y);

}
////////////////////////////End--Yuki Add Upperbody Analysis//////////////////////////////////////////////


///////////////////////////Michael Add ����ӿ����///////////////////////////////////////////////
void CATMFaceSelect::SetROI( int x, int y, int width, int height )
{
	m_rcROI = cvRect( x, y, width, height );
}

void CATMFaceSelect::SetFaceParas( int iMinFace, double dFaceChangeRatio )
{
	m_iFaceSize = iMinFace;
	m_dFaceChangeRatio = dFaceChangeRatio;
}

void CATMFaceSelect::SetDwSmpRatio( double dRatio )
{
	if( fabs( dRatio - 1.0 ) < 0.1f )
	{
		m_bScaleFaceDetection = 0;
	}
	else
	{
		m_bScaleFaceDetection = 1;
		m_dScale = dRatio;
	}
}

void CATMFaceSelect::SetExRatio( double topExRatio, double bottomExRatio, double leftExRatio, double rightExRatio )
{
	m_ExRatio_t = topExRatio;
	m_ExRatio_b = bottomExRatio;
	m_ExRatio_l = leftExRatio;
	m_ExRatio_r = rightExRatio;
}
/////////////////////////End -- Michael Add ����ӿ����////////////////////////////////////////
